For WWW-Form, it was decided that the test scripts should use Test::More, but if it isn't available on the system (say because of an older Perl, then the test script will exit immediately with an empty plan. To do that I wrote the following code in a module called CondTestMore.pm (short for "Conditional Test::More"):
# This is an assisting module. It makes sure Test::More is present, and if not # gracefully exists. Otherwise it behaves the same as Test::More. # package CondTestMore; use vars qw(@ISA); @ISA=qw(Test::More); BEGIN { eval { require Test::More; }; if ($@) { warn "You don't have Test::More. Terminating"; print "1..0\n"; exit 0; } } 1;
This worked fine at the time. However, recently someone on the IRC asked me why CondTestMore did not work anymore. I tested it with perl-5.8.8 and it indeed didn't work. It still worked with perl-5.8.7 and other versions however. A closer inspection showed that the problem was caused by recent versions of Test::More.
As it turned out Test::More converted to using Test::Builder::Module, from which in turn inherits from the "Exporter" module, and supplies its own import function, which looks like this:
sub import { my($class) = shift; my $test = $class->builder; my $caller = caller; $test->exported_to($caller); $class->import_extra(\@_); my(@imports) = $class->_strip_imports(\@_); $test->plan(@_); $class->$_export_to_level(1, $class, @imports); }
Pretty funky, no? Well, Since CondTestMore inherits from Test::More it broke the Exporter logic, and so the ok() is() etc. methods were not exported. After playing a bit with my Perl code, I eventually was able to implement CondTestMore like this, so it will work with the newer Test::More:
package CondTestMore; BEGIN { eval { require Test::More; }; if ($@) { warn "You don't have Test::More. Terminating"; print "1..0\n"; exit 0; } Test::More->import(); @ISA = qw(Test::More); *EXPORT = \@Test::More::EXPORT; } 1;
Here, I import the Test::More symbols into the CondTestMore package, and also make CondTestMore's @EXPORT point there, so Test::Builder::Module will like it this way. This seems to work for what I need to do.
So it's a regression, but I'm not sure anyone was supposed to inherit from Test::More in this way.
As you'll likely have to bundle this module with the distribution, have you thought of bundling Test::More
itself? That seems like less work to me.
Re:An Alternate Thought
Shlomi Fish on 2006-11-21T20:56:47
Hi. I knew you were going to suggest that before I read your post here, because I thought about it too earlier. Well, this idea did not cross the minds of the WWW::Form originator and me when we first implemented "CondTestMore". However, now that I think of it, I believe it would be sub-optimal because bundling Test::More and all of its dependencies (like Test::Builder) will increase the size of the WWW::Form distribution considerably. So I guess we'll stick with CondTestMore for the time being.
I should note that for my own modules, I'm making a heavy use of Test::More, and don't condition its usage like that. I only implemented the CondTestMore scheme in WWW::Form due to the original author feedback, since when manually installing the module using perl Makefile.PL, you only get a warning that Test::More is absent, and still get tests' failure.
Re:An Alternate Thought
chromatic on 2006-11-21T22:07:35
Okay, so instead of adding one line to your Makefile.PL or a few kilobytes to the distribution size, you want to maintain your own code that doesn't do as much, takes more work to maintain, has no other users, and increases your testing burden by adding an entirely new test path, when there is one really good way to solve this problem (mark
Test::More
as a dependency in your build file) and one decent way to solve this problem (bundleTest::More
).I have some weird hobbies too, but
... wow. Good luck with that. Re:An Alternate Thought
Shlomi Fish on 2006-11-22T04:39:00
Actually, the Makefile.PL does specify a dependency on Test::More. We just still want to have CondTestMore in case a user on an older perl installation that doesn't have Test::More, tries to build it from the source without using CPAN.pm/CPANPLUS.pm.